#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <sys/time.h>
#include <string.h>
#include <sys/signal.h>
#include <sys/wait.h>
#include <sys/resource.h>
#include <ctype.h>
#include <sys/errno.h>
#include <sys/stat.h> /* Function to take information from a file */
#include <math.h>
#include <syslog.h>
#include <netdb.h>
#include <fcntl.h>
#include <sys/shm.h>
#include "../Headers/comm_shm.h"
#include "../Headers/shared.h"
#include "../Headers/sem.h"

#define MAX_MSG_SIZE 255

struct shmCDT{
    char * pshm;
    int offset;
    int sem;
};

shmADT 
open_conn_shm (hostSHM * phost)
{
    shmADT shm;
    int auxshm, auxsem;
    int new_key;
    int new_offset;
    char mypid[PID_LEN] = {0};
    void * pshm;
    char * cpshm;
    
    if (phost->shm_id < 0 || phost->sem_id < 0)
        return NULL;
        
    if ((shm = malloc (sizeof (struct shmCDT))) == NULL)
        return NULL;
    
    /* Abro SHM y Semaforo para pedir conexion */
    if ((auxshm = shmget (phost->shm_id, MAX_MSG_SIZE, 0666)) == -1){
        free (shm);
        return NULL;
    }
    if ((pshm = shmat (auxshm, NULL, 0666)) == (void*) -1){
        free (shm);
        return NULL;
    }     
    cpshm = (char*) pshm;
    if ((auxsem = initsem(phost->sem_id)) == -1)
    {
        free (shm);
        return NULL;
    }
    
    /* Hago un pedido de conexion cuando el SHM este libre y el flag lo permite */
    while (p(auxsem)){
        if (cpshm[0] != 0){
            v(auxsem);
            usleep (500000);
        }
        else
            break;
    }
    
    cpshm[0] = 1;
    sprintf (mypid, "%d", getpid());
    strcpy (cpshm + 1, mypid);
    v(auxsem);
    
    /* Le doy tiempo a q me responda */
    sleep (2);
    
    /* Leo la repsuesta */
    p(auxsem);
    sscanf (cpshm + 1, "%d %d", &new_key, &new_offset);
    putZeros (cpshm, MAX_MSG_SIZE);
    v(auxsem);
    
    /* Me desacoplo de esa zona de memoria */
    shmdt (pshm);
    
    /* Me acoplo a la zona de memoria q se usa para mensajes
     * con la key que me dejo el servidor */
    if ((pshm = shmat (new_key, NULL, 0666)) == (void*) -1){
        free (shm);
        return NULL;
    }
    shm->pshm = (char *) pshm;
    shm->offset = new_offset;
    /* Abro un semaforo con mi pid como key */
    if ((auxsem = initsem(getpid())) == -1)
    {
        shmdt (pshm);
        free (shm);
        return NULL;
    }     
    shm->sem = auxsem;
           
    return shm;
}

/* Envia Informacion */
int 
send_data_shm (shmADT conn, char * s_msg, int size)
{
	
    while (p(conn->sem)){
        if (conn->pshm[conn->offset+1] != 0){
            v(conn->sem);
            usleep (500000);
        }
        else
            break;
    }
    /* Para indicar que hay un mensaje nuevo */
    *(conn->pshm + conn->offset + 1) = 1; 
    strcpy (conn->pshm + conn->offset + 2, s_msg);
    v(conn->sem);
    
    return 1;
}

/* Recibe Informacion */
int
rcv_data_shm (shmADT conn, char * r_msg)
{
    p (conn->sem);
    strcpy (r_msg, conn->pshm + conn->offset + 2);
    putZeros (conn->pshm + conn->offset + 1, MAX_MSG_SIZE + 1);
    v(conn->sem);  
    
    return 1;  
}

/* Cerrar Conexion */
int 
close_conn_shm (shmADT conn)
{
    p (conn->sem);
    /* Para indicar que me desconecto */
    *(conn->pshm + conn->offset + 1) = 3; 
    v(conn->sem);
    shmdt (conn->pshm);
    free (conn);
    
    return 1;
}

int getFd_shm(shmADT conn);
